var terrainEffectVertexShaderStr = "\
attribute vec3 inPosition;\
attribute vec3 inNormal;\
uniform mat4 viewProjectionMat;\
uniform mat4 shadowMat;\
uniform vec3 translateToWorld;\
uniform vec3 vertexParam;\
uniform vec4 materialBlendFactor;\
uniform vec3 lightData[3];\
uniform vec3 ambient;\
uniform vec3 diffuse;\
varying vec2 outTexCoord0;\
varying vec2 outMaterialUV;\
varying vec4 outSplatFactor;\
varying vec4 shadowCoord;\
varying vec3 ambientColor;\
varying vec3 diffuseColor;\
void main(void)\
{\
  vec3 worldPos = (inPosition+translateToWorld);\
  shadowCoord = shadowMat*vec4(worldPos,1.0);\
  shadowCoord.z-=0.002;\
  shadowCoord = vec4( shadowCoord.xyz/shadowCoord.w,shadowCoord.w);\
  vec2 texCoords = (worldPos.xz /vertexParam.x) + vec2(0.5,0.5);\
  texCoords.t = 1.0-texCoords.t;\
  gl_Position = viewProjectionMat*vec4(worldPos,1.0);\
  outTexCoord0 = texCoords;\
  outMaterialUV = (worldPos.xz/vertexParam.z);\
  float distanceFromCenter = length(inPosition);\
  outSplatFactor = materialBlendFactor*(1.0-distanceFromCenter/vertexParam.y);\
  outSplatFactor = clamp(outSplatFactor,0.0,1.0);\
  vec3 N = normalize(inNormal);\
  float _diffuse = max(dot(N,lightData[0]),0.0);\
  ambientColor = ambient*lightData[1];\
  diffuseColor = _diffuse*lightData[2]*diffuse;\
}\
";
var terrainEffectFragmentShaderStr = "\
varying vec3 ambientColor;\
varying vec3 diffuseColor;\
varying vec2 outTexCoord0;\
varying vec2 outMaterialUV;\
varying vec4 outSplatFactor;\
varying vec4 shadowCoord;\
uniform sampler2D textureMap;\
uniform vec3 lightData[3];\
uniform sampler2D alphaMap;\
uniform sampler2D materialTex0;\
uniform sampler2D materialTex1;\
uniform sampler2D materialTex2;\
uniform sampler2D materialTex3;\
uniform sampler2D shadowMap;\
uniform vec2 fragmentParam;\
float lookup(vec2 offset)\
{\
  vec4 mapDepth = texture2D(shadowMap,shadowCoord.st+ offset );\
  float distanceFromLight = mapDepth.x + mapDepth.y/256.0+mapDepth.z/65536.0;\
  float shadow = distanceFromLight < shadowCoord.z?fragmentParam.x:1.0 ;\
  return shadow;\
}\
void main(void)\
{\
  vec4 main_tex_color = texture2D(textureMap,outTexCoord0);\
  vec4 material0,material1,material2,material3;\
  vec4 finalColor;\
  float shadow = 1.0;\
  vec4 mapDepth = texture2D(shadowMap,shadowCoord.st);\
  if(!all( equal(mapDepth,1.0))&& shadowCoord.w > 0.0&&  all(greaterThanEqual(shadowCoord.st,0.0))&&all(lessThanEqual(shadowCoord.st,1.0)) ){\
    shadow=0.0;\
    float sm_offset = fragmentParam.y;\
    shadow+=lookup( vec2(sm_offset,sm_offset));\
    shadow+=lookup( vec2(-sm_offset,sm_offset));\
    shadow+=lookup( vec2(sm_offset,-sm_offset));\
    shadow+=lookup( vec2(-sm_offset,-sm_offset));\
    shadow/=4.0;\
  }\
  vec4 alpha = texture2D(alphaMap,outTexCoord0);\
  alpha.a = 1.0-alpha.a;\
  alpha*=outSplatFactor;\
  material0 = texture2D(materialTex0, outMaterialUV)*alpha.r;\
  material1 = texture2D(materialTex1, outMaterialUV)*alpha.g;\
  material2 = texture2D(materialTex2, outMaterialUV)*alpha.b;\
  material3 = texture2D(materialTex3, outMaterialUV)*alpha.a;\
  finalColor = vec4( (main_tex_color*(1.0- (alpha.r+alpha.g+alpha.b+alpha.a))*vec4(lightData[1],1.0)+ (material0+material1+material2+material3)*vec4(diffuseColor+ambientColor,1.0) ).rgb*shadow,1.0);\
  gl_FragColor = finalColor;\
}\
";
function gewTerrainEffect(game)
{
  // General properties
  this.game = game;
  this.gl = game.gl;
  var gl = game.gl;
  this.name = "TerrainEffect";
  this.scene3d = null;//Current scene3d that using this effect 
  this.materialList = {};
  this.currentPass = null;   
  // Shader properties
  this.shader = {};
  createGLSLShader(gl,this.shader,terrainEffectVertexShaderStr,terrainEffectFragmentShaderStr);
}
gewTerrainEffect.prototype.destructor = function()
{
  var list  = this.materialList;
  var listLen = list.length;  
  for (var i in list)
  {
    list[i].destructor();
  }
  this.scene3d.removeEffect(this);
},
gewTerrainEffect.prototype.render = function(scene3d) 
{
  var gl = this.gl; 
  this.scene3d = scene3d;
  // push GL state
  // set GL state
  var shader = this.shader;
  gl.useProgram(shader.program);
  gl.enableVertexAttribArray(shader.inPosition);
  gl.enableVertexAttribArray(shader.inNormal);
  gl.enable(gl.DEPTH_TEST);
  //gl.enable(gl.CULL_FACE);
  // render pass 0 with all material
  this.currentPass = 0;
  var light = scene3d.mainLight;
  gl.uniform3fv(shader.lightData,light.lightData);
  var shadowMat = light.shadowMat;
  gl.uniformMatrix4fv(shader.shadowMat, false, shadowMat.data);
  var materialList = this.materialList;
  var listLen = materialList.length;
  for(var i in materialList)
  {
    materialList[i].render();
  }
  //
  gl.currentPass = null;
  // pop GL state  
  gl.disable(gl.DEPTH_TEST);
  //gl.disable(gl.CULL_FACE);
  gl.disableVertexAttribArray(shader.inPosition);
  gl.disableVertexAttribArray(shader.inNormal);
}